package net.jcip.examples.chapter6;

import java.util.*;
import java.util.concurrent.*;
import static net.jcip.examples.LaunderThrowable.launderThrowable;

/**
 * Renderer
 * <p/>
 * Using CompletionService to render page elements as they become available
 *
 * @author Brian Goetz and Tim Peierls
 */
public abstract class Renderer {
    private final ExecutorService executor;

    Renderer(ExecutorService executor) {
        this.executor = executor;
    }

    void renderPage(CharSequence source) {
        final List<ImageInfo> info = scanForImageInfo(source);
        CompletionService<ImageData> completionService = new ExecutorCompletionService<>(executor);
        //每一张图片的下载 开启一个线程
        //这里没有考虑线程的数量， 实际需要根据线程的大小来判断是否需要根据图片的数量  进行任务划分，比如每个线程下载几张图片
        for (final ImageInfo imageInfo : info)
            completionService.submit(() -> imageInfo.downloadImage());

        renderText(source);

        try {
            for (int t = 0, n = info.size(); t < n; t++) {
                //通过 take() 方法获取已完成的任务的结果。如果当前没有已完成的任务，take() 方法会阻塞，直到有任务完成。
                //结果按照任务完成的顺序返回，而不是按照任务提交的顺序。
                Future<ImageData> f = completionService.take();
                ImageData imageData = f.get();
                renderImage(imageData);
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } catch (ExecutionException e) {
            throw launderThrowable(e.getCause());
        }
    }

    interface ImageData {
    }

    interface ImageInfo {
        ImageData downloadImage();
    }

    abstract void renderText(CharSequence s);

    abstract List<ImageInfo> scanForImageInfo(CharSequence s);

    abstract void renderImage(ImageData i);

}
